package com.revzone.demo001.controller;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.revzone.demo001.entity.*;

import com.revzone.demo001.mapper.UploadMapper;
import com.revzone.demo001.service.UploadService;
import io.swagger.annotations.ApiOperation;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.core.io.InputStreamResource;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.URLEncoder;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.StandardCopyOption;
import java.time.LocalDateTime;
import java.util.*;
import java.util.concurrent.atomic.AtomicLong;

@RestController
@RequestMapping("/upload")
public class UploadController {

    //监测报告路径
    @Value("${revzone.PIC_ADDRESS}")
    private String PIC_ADDRESS ;
    @Autowired
    UploadService uploadService;

    @Autowired
    UploadMapper uploadMapper;

    @PostMapping(value="/list", produces = "application/json;charset=UTF-8")
    public Result listResources(@RequestBody(required = false) Upload upload ) {
        QueryWrapper<Upload> wrapper = new QueryWrapper<>();
        if (upload.getPro_id() != null) {
            wrapper.eq("pro_id", upload.getPro_id());
        }
        return Result.success(uploadService.list(wrapper));
    }

    //上传监测报告
    @PostMapping(value="/add", produces = "application/json;charset=UTF-8")
    @Transactional  // 加上 @Transactional 注解，确保事务管理
    public Result addResource(@RequestParam(required = false) MultipartFile[]  imageFiles, @RequestParam(required = false) String name ) {
        // 确保 PatrolMap 和 imageFile 不为空
        String imagePath = null;
        //首先判断有对应上工件批次号
        QueryWrapper<Upload> wrapper = new QueryWrapper<>();
        wrapper.eq("pro_id", name);
        if(uploadMapper.selectList(wrapper) == null){
            return Result.error("没有对应上工件批次号" );
        }
        if (name != null && imageFiles != null) {
            // 设置文件路径+批次号
            imagePath = PIC_ADDRESS + File.separator + name;

            // 创建目标目录，如果目录不存在则创建
            Path directoryPath = Paths.get(imagePath);
            if (!Files.exists(directoryPath)) {
                try {
                    Files.createDirectories(directoryPath);  // 创建目录及父目录
                } catch (IOException e) {
                    e.printStackTrace();
                    return Result.error("文件目录创建失败");
                }
            }
            // 创建文件保存路径
            List<Map<String, Object>> resultList = new ArrayList<>();
            Set<String> seenNames = new HashSet<>();
            boolean hasDuplicates = false;
            for (MultipartFile imageFile : imageFiles) {
                try {

                    String originalFilename = imageFile.getOriginalFilename();
                    Map<String, Object> fileResult = new HashMap<>();
                    fileResult.put("file", Map.of(
                            "originalName", originalFilename,
                            "size", imageFile.getSize()
                    ));
                    //判断有重名的图片需要将重复的返回报错，说明是文件名问题，需要再次提交
                    // 检查本次上传的文件名是否重复
                    if (seenNames.contains(originalFilename)) {
                        fileResult.put("msg", "与本次上传的其他文件重复");
                        hasDuplicates = true;
                    } else {
                        fileResult.put("msg", "成功");
                    }

                    // 创建文件保存路径
                    Path filePath = Paths.get(imagePath + File.separator + originalFilename);
                    Files.copy(imageFile.getInputStream(), filePath, StandardCopyOption.REPLACE_EXISTING);
                    resultList.add(fileResult);
                    seenNames.add(originalFilename);

                }
                catch (IOException e) {
                    e.printStackTrace();
//                    System.err.println("图片上传失败: " + imageFile.getOriginalFilename() + ", 错误: " + e.getMessage());
                    return Result.error("图片上传失败" + imageFile.getOriginalFilename() + ", 错误: " + e.getMessage());
                }
            }
            // 4. 如果有重复文件，返回错误信息
            if (hasDuplicates) {
                return Result.success("存在重复文件名", resultList);
            }
        }
        // 批量更新同批次号（pro_id=name）的所有数据
        if (name != null && imagePath != null) {
            Upload updateUpload = new Upload();
            updateUpload.setReport(1);
            updateUpload.setReport_name(name);
            updateUpload.setReport_time(LocalDateTime.now());
            updateUpload.setUpdate_time(LocalDateTime.now());
            updateUpload.setReport_path(imagePath);
            // 使用 MyBatis-Plus 的 update方法，构造条件
            QueryWrapper<Upload> updateWrapper = new QueryWrapper<>();
            updateWrapper.eq("pro_id", name);
            int updateCount = uploadMapper.update(updateUpload, updateWrapper);
            return Result.success(updateCount);//更新条数
        } else {
            return Result.error("参数缺失");
        }
    }
    //对重名文件的判断，重名失败的话返回名字和原因
    //打包文件解开录入物品图和唯一码
    @PostMapping(value="/batchAddFromFolder", produces = "application/json;charset=UTF-8")
    @Transactional
    public Result batchAddFromFolder(@RequestParam(required = false) MultipartFile[]  imageFiles, @RequestParam(required = false) String name ) {
        String imagePath = PIC_ADDRESS + File.separator + name + "workpiece";
        // 创建目标目录，如果目录不存在则创建
        Path directoryPath = Paths.get(imagePath);
        if (!Files.exists(directoryPath)) {
            try {
                Files.createDirectories(directoryPath);  // 创建目录及父目录
            } catch (IOException e) {
                e.printStackTrace();
                return Result.error("文件目录创建失败");
            }
        }
        // 1. 计算所有图片的的总字节数
        long totalFileSize = 0;
        for (MultipartFile imageFile : imageFiles) {
            totalFileSize += imageFile.getSize();
        }
        // 使用 AtomicLong 来安全地追踪所有文件已上传的总字节数
        AtomicLong totalBytesRead = new AtomicLong(0);

        List<Map<String, Object>> resultList = new ArrayList<>();
        Set<String> seenNames = new HashSet<>();
        boolean hasDuplicates = false;
        int successCount = 0;
        int failCount = 0;
        for (MultipartFile imageFile : imageFiles) {
            try {

                String originalFilename = imageFile.getOriginalFilename();
                int slashIndex = originalFilename.indexOf('/');
                originalFilename = originalFilename.substring(slashIndex+1);

                Map<String, Object> fileResult = new HashMap<>();
                fileResult.put("file", Map.of(
                        "originalName", originalFilename,
                        "size", imageFile.getSize()
                ));
                String fileName = originalFilename;
                fileName = fileName.substring(0, fileName.lastIndexOf('.'));
                //判断有重名的图片需要将重复的返回报错，说明是文件名问题，需要再次提交
                QueryWrapper<Upload> wrapper = new QueryWrapper<>();
                wrapper.eq("name", fileName);
                List<Upload> repeatfile = uploadMapper.selectList(wrapper);
                if(repeatfile.size() != 0){
                    fileResult.put("msg", "与已存在的其他文件重复");
                    failCount++;
                    resultList.add(fileResult);
                    continue;
                }
                // 检查本次上传的文件名是否重复
                if (seenNames.contains(originalFilename)) {
                    fileResult.put("msg", "与本次上传的其他文件重复");
                    hasDuplicates = true;
                } else {
                    fileResult.put("msg", "成功");

                    Upload upload = new Upload();
                    upload.setPath(imagePath + File.separator + originalFilename);
                    upload.setCreate_time(LocalDateTime.now());
                    upload.setUpdate_time(LocalDateTime.now());
                    upload.setName(fileName);
                    upload.setRemarks("批量导入");
                    upload.setPro_id(name);
                    int result = uploadMapper.insert(upload);
                    if (result > 0) successCount++;
                    // 创建文件保存路径
                    Path filePath = Paths.get(imagePath + File.separator + originalFilename);
                    InputStream fileInputStream = imageFile.getInputStream();
                    //汇报进度
                    ProgressCountingInputStream progressStream = new ProgressCountingInputStream(fileInputStream, totalFileSize, totalBytesRead);
                    Files.copy(progressStream, filePath, StandardCopyOption.REPLACE_EXISTING);
                }


                resultList.add(fileResult);
                seenNames.add(originalFilename);
            }
            catch (IOException e) {
                e.printStackTrace();
                return Result.error("图片上传失败" + imageFile.getOriginalFilename() + ", 错误: " + e.getMessage());
            }
        }
        // 4. 如果有重复文件，返回错误信息
        if (hasDuplicates) {
            return Result.success("存在重复文件名", resultList);
        }
        return Result.success(failCount>0? 202:200,"成功导入图片数量: " + successCount + " 失败图片数量" + failCount ,resultList);
    }
    //唯一码查图片
    @GetMapping(value="/getFile", produces = "application/json;charset=UTF-8")
    @ApiOperation(value = "查询对应图片！")
    public ResponseEntity<?> getFile(@RequestParam(required = false) Integer id ) throws IOException {
        // 从数据库获取 mapAddress
        Upload upload = uploadMapper.selectById(id);
        String mapAddress = upload.getPath();

        // 假设 mapAddress 是存储图片的绝对路径
        File file = new File(mapAddress);

        if (file.exists() && file.isFile()) {
            // 使用 FileInputStream 来读取文件
            FileInputStream fileInputStream = new FileInputStream(file);
            long fileLength = file.length();

            // 使用 Files.probeContentType() 来自动获取文件的 MIME 类型
            Path filePath = file.toPath();
            String mimeType = Files.probeContentType(filePath);

            // 设置响应头
            HttpHeaders headers = new HttpHeaders();
            headers.add(HttpHeaders.CONTENT_DISPOSITION, "inline; filename=" + file.getName());  // 以图片方式返回
            headers.add(HttpHeaders.CONTENT_LENGTH, String.valueOf(fileLength));  // 文件大小

            // 如果 MIME 类型为空，设置默认的图片类型。MIME动态获取图片类型
            if (mimeType == null) {
                mimeType = "application/octet-stream";  // 默认返回二进制流
            }

            // 返回图片内容，使用 InputStreamResource
            InputStreamResource resource = new InputStreamResource(fileInputStream);
            return ResponseEntity.ok()
                    .headers(headers)
                    .contentType(MediaType.parseMediaType(mimeType))  // 设置动态获取的 MIME 类型
                    .body(resource);  // 返回 InputStreamResource 作为响应体
        } else {
            // 文件不存在，返回 404
            return ResponseEntity.notFound().build();
        }
    }
    //多张图片查询
    @GetMapping(value="/getReportFile", produces = "application/json;charset=UTF-8")
    @ApiOperation(value = "查询对应图片！")
    public ResponseEntity<?> getReportFile(@RequestParam(required = false) String path) throws IOException {

        String mapAddress = path;

        // 假设 mapAddress 是存储图片的绝对路径
        File folder  = new File(mapAddress);

        // 2. 验证路径是否是文件夹
        if (!folder.exists() || !folder.isDirectory()) {
            return ResponseEntity.status(HttpStatus.BAD_REQUEST)
                    .body(Collections.singletonMap(500, "指定路径不是文件夹或不存在"));
        }

        // 3. 读取文件夹中的所有图片文件
        File[] imageFiles = folder.listFiles((dir, name) -> {
            String lowerName = name.toLowerCase();
            return lowerName.endsWith(".jpg") ||
                    lowerName.endsWith(".jpeg") ||
                    lowerName.endsWith(".png") ||
                    lowerName.endsWith(".gif") ||
                    lowerName.endsWith(".bmp");
        });

        if (imageFiles == null || imageFiles.length == 0) {
            return ResponseEntity.ok(Collections.emptyList());
        }

        // 4. 转换为图片URL列表
        List<Map<String, String>> imageList = new ArrayList<>();
        for (File imageFile : imageFiles) {
            Map<String, String> imageInfo = new HashMap<>();
            imageInfo.put("fileName", imageFile.getName());
            imageList.add(imageInfo);
        }



        return ResponseEntity.ok()
                .body(Result.success(imageList));
    }
    //多张图片查询
    @GetMapping(value="/getSingleImage", produces = "application/json;charset=UTF-8")
    @ApiOperation(value = "查询对应图片！")
    public ResponseEntity<?> getSingleImage(@RequestParam(required = false) String path,
                                            @RequestParam(required = false) String fileName) throws IOException {

        if(path == null || fileName == null) return ResponseEntity.ok(Result.error("缺少文件名或路径"));

        //获取图片
//        String safeFileName = new File(fileName).getName();
        File imageFile = new File(path, fileName);

        // 验证文件是否存在且是图片
        if (!imageFile.exists() || !imageFile.isFile()) {
            return ResponseEntity.notFound().build();
        }
        else {
            // 4. 返回图片内容
            FileInputStream fileInputStream = new FileInputStream(imageFile);
            String mimeType = Files.probeContentType(imageFile.toPath());
            if (mimeType == null || !mimeType.startsWith("image/")) {
                return ResponseEntity.status(HttpStatus.UNSUPPORTED_MEDIA_TYPE)
                        .body("不是有效的图片文件");
            }

            HttpHeaders headers = new HttpHeaders();
            headers.add(HttpHeaders.CONTENT_DISPOSITION, "inline; filename=" + fileName);
            InputStreamResource resource = new InputStreamResource(fileInputStream);
            return ResponseEntity.ok()
                    .headers(headers)
                    .contentType(MediaType.parseMediaType(mimeType))
                    .body(resource);
        }
    }

    //唯一码查询所有内容
    @PostMapping(value="/information", produces = "application/json;charset=UTF-8")
    public Result information(@RequestBody(required = false) Upload upload) {

        QueryWrapper<Upload> queryWrapper = new QueryWrapper<>();
        if(upload.getName()!=null){
            queryWrapper.eq("name", upload.getName());
        }
        return Result.success(uploadMapper.selectOne(queryWrapper));
    }
    //根据批次号分组,分页
    @PostMapping(value="/group", produces = "application/json;charset=UTF-8")
    public Result groupbyproid(@RequestBody(required = false) PageResultMap<UploadGroup> pageResultMap) {
        UploadGroup uploadGroup = new UploadGroup();
        QueryWrapper<UploadGroup> wrapper = new QueryWrapper<>();
            if(pageResultMap != null) {
                if (pageResultMap.map != null) {
                    BeanUtils.copyProperties(pageResultMap.map, uploadGroup);
                    //查询group
                    if (uploadGroup.getPro_id() != null) wrapper.eq("pro_id",uploadGroup.getPro_id());
                }
            }else pageResultMap = new PageResultMap<>();
        try
        {
            Page<UploadGroup> taskPage = uploadService.groupByProIdPage(pageResultMap);
            PageResult<UploadGroup> result = new PageResult<UploadGroup>(taskPage);
            return Result.success(result);
        } catch (Exception e) {
            return Result.error("分组查询失败: " + e.getMessage());
        }
    }
    //根据批次号分组,分页
    @PostMapping(value="/grouplist", produces = "application/json;charset=UTF-8")
    public Result groupList() {
        return Result.success(uploadMapper.groupList());
    }

    @PostMapping(value="/page", produces = "application/json;charset=UTF-8")
    public Result pageResources(@RequestBody(required = false) PageResultMap<Upload> pageResultMap ) {
        Upload upload = new Upload();
        Page<Upload> taskPage;
        QueryWrapper<Upload> wrapper = new QueryWrapper<>();
        if (pageResultMap != null) {
            if (pageResultMap.map != null) {
                BeanUtils.copyProperties(pageResultMap.map,upload);
                //查询group
                if (upload.getPro_id() != null) wrapper.eq("pro_id",upload.getPro_id());
            }
        } else pageResultMap = new PageResultMap<>();
        try {
            Page<Upload> page = new Page<>(pageResultMap.getCurrentPage(),pageResultMap.getPageSize());
            wrapper.orderByAsc("id");
            taskPage = uploadService.page(page, wrapper);
        } catch (BeansException e) {
            throw new RuntimeException(e);
        }
        // 将查询结果封装到 PageResult 类型的对象中
        PageResult<Upload> result = new PageResult<Upload>(taskPage);
        return Result.success(result);
    }

    @PostMapping(value="/update", produces = "application/json;charset=UTF-8")
    public Result updateResource(@RequestBody(required = false) Upload upload) {
        return Result.success(uploadService.updateById(upload));
    }

    @Transactional
    @GetMapping(value="/delete", produces = "application/json;charset=UTF-8")
    public Result deleteResource(@RequestParam(required = false) Integer id) {
        //
        Upload upload = uploadMapper.selectById(id);
        if(upload == null){
            return Result.error("未找到该条数据");
        }
        if(cleanPiece(upload.getPath()) && uploadService.removeById(id)){
            return Result.success("单条成功删除");
        }
        else{
            return Result.error("单条删除失败");
        }

    }

    @Transactional
    @GetMapping(value="/deletebyproId", produces = "application/json;charset=UTF-8")
    public Result deleteProidResource(@RequestParam(required = false) String proId) {

        if(proId == null) return Result.error("没有该批次号");
        String pathPiece =PIC_ADDRESS+File.separator+proId+"workpiece";
        String pathReport=PIC_ADDRESS+File.separator+proId;
        boolean cleanpathPiece = cleanDirectory(pathPiece);
        boolean cleanpathReport =cleanDirectory(pathReport);
        boolean deleteList = uploadMapper.deleteList(proId);

        if(deleteList && cleanpathPiece && cleanpathReport){
            return Result.success("成功删除");
        }
        else{
            return Result.error("删除失败");
        }

    }
    @Transactional
    public boolean cleanDirectory(String directoryPath) {
        Path path = Paths.get(directoryPath);

        // 检查文件是否存在
        if (!Files.exists(path)|| !Files.isDirectory(path)) {
            return false;
        }
        try {
            // 使用 Files.walk 遍历目录，并按文件深度降序排序
            // 这样可以确保先删除子文件和子目录，最后处理父目录
            Files.walk(path)
                    .sorted(Comparator.reverseOrder())
                    .forEach(p -> {
                        try {
                            // 避免删除根目录本身
                            if (!p.equals(path)) {
                                Files.delete(p);
                            }
                        } catch (IOException e) {

                        }
                    });
            Files.delete(path);
            return true;
        } catch (IOException e) {
            return false ;
        }
    }
    @Transactional
    public boolean cleanPiece(String directoryPath) {
        Path path = Paths.get(directoryPath);

        // 检查目录是否存在
        if (!Files.exists(path)) {
            return false;
        }
        try {
            Files.delete(path);
            return true;
        } catch (IOException e) {
            return false ;
        }
    }
}

